function isStringAround(node, start, end) { return node.type == "Literal" && typeof node.value == "string" &&
node.start == start - 1 && node.end <= end + 1;
function findCompletions(srv, query, file) { if (query.end == null) throw ternError("missing .query.end field"); var wordStart = resolvePos(file, query.end), wordEnd = wordStart, text = file.text;
while (wordStart && acorn.isIdentifierChar(text.charCodeAt(wordStart - 1))) --wordStart;
if (query.expandWordForward !== false)
while (wordEnd < text.length && acorn.isIdentifierChar(text.charCodeAt(wordEnd))) ++wordEnd;
var word = text.slice(wordStart, wordEnd), completions = [];
if (query.caseInsensitive) word = word.toLowerCase();
var wrapAsObjs = query.types || query.depths || query.docs || query.urls || query.origins;
function gather(prop, obj, depth) { if (query.omitObjectPrototype !== false && obj == srv.cx.protos.Object && !word) return;
if (query.filter !== false && word &&
(query.caseInsensitive ? prop.toLowerCase() : prop).indexOf(word) != 0) return;
for (var i = 0; i < completions.length; ++i) { if ((wrapAsObjs ? c.name : c) == prop) return;
var rec = wrapAsObjs ? {name: prop} : prop; if (query.types || query.docs || query.urls || query.origins) { var val = obj ? obj.props[prop] : infer.ANull;
var type = val.getType();
rec.guess = infer.didGuess();
rec.type = infer.toString(type);
maybeSet(rec, "doc", val.doc || type && type.doc);
maybeSet(rec, "url", val.url || type && type.url);
maybeSet(rec, "origin", val.origin || type && type.origin);
if (query.depths) rec.depth = depth;
var memberExpr = infer.findExpressionAround(file.ast, null, wordStart, file.scope, "MemberExpression");
(memberExpr.node.computed ? isStringAround(memberExpr.node.property, wordStart, wordEnd)
: memberExpr.node.object.end < wordStart)) { var prop = memberExpr.node.property;
prop = prop.type == "Literal" ? prop.value.slice(1) : prop.name;
memberExpr.node = memberExpr.node.object;
var tp = infer.expressionType(memberExpr);
if (tp) infer.forAllPropertiesOf(tp, gather);
if (!completions.length && query.guess !== false && tp && tp.guessProperties) { tp.guessProperties(function(p, o, d) {if (p != prop && p != String.fromCharCode(0x2716)) gather(p, o, d);}); if (!completions.length && word.length >= 2 && query.guess !== false)
for (var prop in srv.cx.props) gather(prop, srv.cx.props[prop][0], 0);
infer.forAllLocalsAt(file.ast, wordStart, file.scope, gather);
if (query.sort !== false) completions.sort(compareCompletions);
return {start: outputPos(query, file, wordStart), end: outputPos(query, file, wordEnd),
completions: completions};
function findProperties(srv, query) {